home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume26 / feedpipe / part01 next >
Encoding:
Text File  |  1991-12-14  |  20.4 KB  |  819 lines

  1. Newsgroups: comp.sources.misc
  2. From: darcy@druid (D'Arcy J.M. Cain)
  3. Subject:  v26i105:  feedpipe - feed a process to a pipe, Part01/01
  4. Message-ID: <1991Dec13.170917.26795@sparky.imd.sterling.com>
  5. X-Md4-Signature: 58585f9551d009cbf949398f18cc0115
  6. Date: Fri, 13 Dec 1991 17:09:17 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: darcy@druid (D'Arcy J.M. Cain)
  10. Posting-number: Volume 26, Issue 105
  11. Archive-name: feedpipe/part01
  12. Environment: UNIX, ANSI-C
  13.  
  14. For information see README.  For convenience this is the first file in
  15. the shar distribution.  Note that an ANSI compiler is required.
  16.  
  17. #!/bin/sh
  18. # This is a shell archive (produced by shar 3.49)
  19. # To extract the files from this archive, save it to a file, remove
  20. # everything above the "!/bin/sh" line above, and type "sh file_name".
  21. #
  22. # made 12/08/1991 15:59 UTC by darcy@druid
  23. # Source directory /usr/darcy/work/feedpipe
  24. #
  25. # existing files WILL be overwritten
  26. #
  27. #                                                                          
  28. #                                                                          
  29. #
  30. # This shar contains:
  31. # length  mode       name
  32. # ------ ---------- ------------------------------------------
  33. #   1777 -rw-r----- README
  34. #   1461 -rw-r----- feedpipe.1
  35. #   4306 -rw-r----- feedpipe.c
  36. #   1610 -rw-r----- readcfg.c
  37. #   5377 -rw-r----- getline.c
  38. #   1613 -rw-rw-r-- Makefile
  39. #    351 -rw-r----- feedpipe.h
  40. #
  41. if test -r _shar_seq_.tmp; then
  42.     echo 'Must unpack archives in sequence!'
  43.     echo Please unpack part `cat _shar_seq_.tmp` next
  44.     exit 1
  45. fi
  46. # ============= README ==============
  47. sed 's/^X//' << 'SHAR_EOF' > 'README' &&
  48. Feedpipe is a program to make processes appear as files (actually a named
  49. pipe) to other processes.  A trivial use of this would be as a random sig
  50. generator.  More useful is to make current information available as a file
  51. to processes such as UUCP.
  52. X
  53. Also included as it is used by feedpipe is my getline function.  Note this
  54. is not quite like the BSD getline.  See that file for details.
  55. X
  56. A man page is provided as feedpipe.1
  57. X
  58. Here is a sample configuration file for it which demonstrates some of the
  59. uses to which I am putting it.
  60. X
  61. ----------------------- Start of configuration file --------------------------
  62. # Configuration file for feedpipe
  63. # Written by D'Arcy J.M. Cain
  64. X
  65. # This file contains the information used by feedpipe to create files
  66. X
  67. # First the information files.  The program pubinfo is basically a cat
  68. # from a here file.  The second entry is the compressed version
  69. /usr/spool/uucppublic/pub/info/readme            uucp uucp 0644 \
  70. X    /usr/lbin/pubinfo
  71. /usr/spool/uucppublic/pub/info/readme.Z            uucp uucp 0644 \
  72. X    /usr/lbin/pubinfo | /usr/lbin/compress
  73. X
  74. # ls -lR of my public directories - note use of echo and date
  75. /usr/spool/uucppublic/pub/info/ls-lR.Z            uucp uucp 0644 \
  76. X    (echo "ls -lR as of \c"; date; ls -lR /usr/spool/uucppublic/pub) | \
  77. X    /usr/lbin/compress
  78. X
  79. # This is the UUCP clone that I am working on.  Note pa is a program that
  80. # creates a cpio archive of a directory and writes it to its stdout.  this
  81. # causes the very latest version of the source tree to be made available
  82. # to UUCP
  83. /usr/spool/uucppublic/pub/archive/uudos.CP.Z    darcy program 0644 \
  84. X    cd /usr/darcy; /usr/lbin/pa uudos 2> /dev/null
  85. ------------------------- end of configuration file --------------------------
  86. X
  87. Any comments, bugs, suggestions etc welcome
  88. X
  89. D'Arcy J.M. Cain
  90. darcy@druid.UUCP
  91. X
  92. SHAR_EOF
  93. chmod 0640 README ||
  94. echo 'restore of README failed'
  95. Wc_c="`wc -c < 'README'`"
  96. test 1777 -eq "$Wc_c" ||
  97.     echo 'README: original size 1777, current size' "$Wc_c"
  98. # ============= feedpipe.1 ==============
  99. sed 's/^X//' << 'SHAR_EOF' > 'feedpipe.1' &&
  100. .TH FEEDPIPE 1L "Local Command"
  101. .SH NAME 
  102. .B feedpipe\^ 
  103. - Feed pipe from command after pipe starts being read
  104. .SH SYNOPSIS 
  105. .B feedpipe\^ 
  106. config_file
  107. .SH DESCRIPTION 
  108. .B Feedpipe
  109. runs a specified command writing the output to a specified
  110. pipe.  After opening the pipe it removes the pipe name and forks
  111. a new process to
  112. do the same thing again.
  113. .PP
  114. The open for writing on the pipe will block until someone opens
  115. the other end.  This means that the command to be run will be
  116. run only when someone reads the pipe.  This is designed to make
  117. the output of the pipe up to date.
  118. .PP
  119. The
  120. .I config_file
  121. is used to tell
  122. .B feedpipe
  123. the details of the feeds.  Each line causes a process to be forked and
  124. a feed started.  The lines are separated into the following space
  125. delimited fields:
  126. .sp
  127. .nf
  128. .in +4
  129. Name of pipe
  130. owner of pipe ("-" means uid of running process)
  131. group of pipe ("-" means gid of running process)
  132. mode to open pipe in
  133. Command to feed to pipe
  134. .in -4
  135. .PP
  136. The command to send consists of all text starting at the second field.
  137. The sequence backslash followed by a newline is ignored allowing large
  138. lines to be split up for readability.  Everything following the "#"
  139. character is ignored as are blank lines after the above substitutions.
  140. No further pre-processing is done on the line so any backslashes, other
  141. than those preceding a newline, are passed to the command.
  142. .SH CAVEAT
  143. You should never put the program to run in a directory writeable by UUCP.
  144. SHAR_EOF
  145. chmod 0640 feedpipe.1 ||
  146. echo 'restore of feedpipe.1 failed'
  147. Wc_c="`wc -c < 'feedpipe.1'`"
  148. test 1461 -eq "$Wc_c" ||
  149.     echo 'feedpipe.1: original size 1461, current size' "$Wc_c"
  150. # ============= feedpipe.c ==============
  151. sed 's/^X//' << 'SHAR_EOF' > 'feedpipe.c' &&
  152. /*
  153. feedpipe.c
  154. Written by D'Arcy J.M. Cain
  155. X
  156. Feeds command to a named pipe
  157. */
  158. X
  159. #include    <stdio.h>
  160. #include    <stdlib.h>
  161. #include    <process.h>
  162. #include    <signal.h>
  163. #include    <io.h>
  164. #include    <string.h>
  165. #include    <errno.h>
  166. #include    <malloc.h>
  167. #include    <pwd.h>
  168. #include    <grp.h>
  169. #include    <sys/stat.h>
  170. #include    "feedpipe.h"
  171. X
  172. /* globals */
  173. FP_CFG    *fp_cfg;
  174. char    *progname;
  175. X
  176. static char    *f_name;
  177. X
  178. static void    cleanup(int sig)
  179. {
  180. X    unlink(f_name);
  181. X    exit(sig);
  182. }
  183. X
  184. /* function called for each line in configuration file */
  185. static void    feedpipe(FP_CFG fc)
  186. {
  187. X    int        child, k, uid, gid;
  188. X    FILE    *pipe_fp, *fp;
  189. X
  190. X    /* fork and check for error */
  191. X    if ((child = fork()) == -1)
  192. X    {
  193. X        fprintf(stderr, "%s: Can't fork (%s)\n", progname, strerror(errno));
  194. X        exit(3);
  195. X    }
  196. X
  197. X    /* if no error and parent process then return immediately */
  198. X    if (child)
  199. X        return;
  200. X
  201. X    /* we are now a new process with a command to run */
  202. X    f_name = fc.name;
  203. X
  204. X    signal(SIGHUP, cleanup);
  205. X    signal(SIGINT, cleanup);
  206. X    signal(SIGTERM, cleanup);
  207. X
  208. X    /* the child doesn't need this array */
  209. X    free(fp_cfg);
  210. X
  211. X    /* mode is for permissions only - it's always a pipe */
  212. X    fc.mode &= 000777;
  213. X    fc.mode |= S_IFIFO;
  214. X
  215. X    if (fc.owner == NULL)
  216. X        uid = getuid();
  217. X    else
  218. X    {
  219. X        struct passwd    *pw;
  220. X
  221. X        if ((pw = getpwnam(fc.owner)) == NULL)
  222. X        {
  223. X            fprintf(stderr, "%s: No such user %s\n", progname, fc.owner);
  224. X            exit(4);
  225. X        }
  226. X
  227. X        uid = pw->pw_uid;
  228. X    }
  229. X
  230. X    if (fc.group == NULL)
  231. X        gid = getgid();
  232. X    else
  233. X    {
  234. X        struct group    *gr;
  235. X
  236. X        if ((gr = getgrnam(fc.group)) == NULL)
  237. X        {
  238. X            fprintf(stderr, "%s: No such group %s\n", progname, fc.group);
  239. X            exit(5);
  240. X        }
  241. X
  242. X        gid = gr->gr_gid;
  243. X    }
  244. X
  245. X    /* this loop may seem a little strange */
  246. X    /* each iteration through it is actually a new process */
  247. X    for (;;)
  248. X    {
  249. X        char    buf[BUFSIZ];
  250. X
  251. X        /* remove any existing file or pipe */
  252. X        unlink(fc.name);
  253. X
  254. X        /* create the new pipe */
  255. X        if (mknod(fc.name, fc.mode, 0))
  256. X        {
  257. X            fprintf(stderr, "%s: Can't create pipe %s (%s)\n",
  258. X                                progname, fc.name, strerror(errno));
  259. X            exit(6);
  260. X        }
  261. X
  262. X        if (chown(fc.name, uid, gid))
  263. X        {
  264. X            fprintf(stderr, "%s: Can't change group and/or owner %s (%s)\n",
  265. X                                progname, fc.name, strerror(errno));
  266. X            exit(7);
  267. X        }
  268. X
  269. X        /* this open will block until someone reads the other end */
  270. X        if ((pipe_fp = fopen(fc.name, "wt")) == NULL)
  271. X        {
  272. X            fprintf(stderr, "%s: Can't open pipe %s (%s)\n",
  273. X                                progname, fc.name, strerror(errno));
  274. X            exit(8);
  275. X        }
  276. X
  277. X        /* when we get here someone is reading the pipe we opened */
  278. X        /* at this point we fork a new process to create the node */
  279. X        /* again and block on opening it - this allows another process */
  280. X        /* to open the same pipe and get the full file after a very */
  281. X        /* short delay */
  282. X
  283. X        /* note that error on fork doesn't stop us immediately */
  284. X        if ((child = fork()) != 0)
  285. X        {
  286. X            /* open the command for reading */
  287. X            if ((fp = popen(fc.cmd, "rt")) == NULL)
  288. X            {
  289. X                fprintf(stderr, "%s: Can't open command %s (%s)\n",
  290. X                                    progname, fc.cmd, strerror(errno));
  291. X                exit(9);
  292. X            }
  293. X
  294. X            /* shovel them bits */
  295. X            while ((k = fread(buf, 1, BUFSIZ, fp)) != 0)
  296. X                fwrite(buf, 1, k, pipe_fp);
  297. X
  298. X            /* cleanup */
  299. X            fclose(fp);
  300. X            fclose(pipe_fp);
  301. X
  302. X            /* now check for failed fork */
  303. X            if (child == -1)
  304. X            {
  305. X                fprintf(stderr, "%s: Can't fork for next %s (%s)\n",
  306. X                                    progname, fc.name, strerror(errno));
  307. X                exit(10);
  308. X            }
  309. X
  310. X            /* exit in any case but with no error */
  311. X            exit(0);
  312. X        }
  313. X
  314. X        /* close the pipe */
  315. X        fclose(pipe_fp);
  316. X    }
  317. }
  318. X
  319. /* start the bubble machine */
  320. int        main(int argc, char **argv)
  321. {
  322. X    FILE    *fp;
  323. X    int        k, nents;
  324. X
  325. X    /* set umask so that config file has full control */
  326. X    umask(0);
  327. X
  328. X    /* get the program name for error messages */
  329. X    if ((progname = strrchr(argv[0], '/')) == NULL)
  330. X        progname = argv[0];
  331. X    else
  332. X        progname++;
  333. X
  334. X    /* we expect one and only one argument currently */
  335. X    if (argc != 2)
  336. X    {
  337. X        fprintf(stderr, "Usage: %s config_file\n", progname);
  338. X        exit(1);
  339. X    }
  340. X
  341. X    /* give it its own process group */
  342. X    setpgrp();
  343. X
  344. X    /* open the configuration file */
  345. X    if ((fp = fopen(argv[1], "rt")) == NULL)
  346. X    {
  347. X        fprintf(stderr, "%s: Can't open configuration file (%s)\n",
  348. X                        progname, strerror(errno));
  349. X        exit(2);
  350. X    }
  351. X
  352. X    /* and read it */
  353. X    if (!(nents = readcfg(fp)))
  354. X        exit(errno);
  355. X
  356. X    /* start a process for each active line */
  357. X    for (k = 0; k < nents; k++)
  358. X        feedpipe(fp_cfg[k]);
  359. X
  360. X    /* free the memory in the parent process and exit */
  361. X    free(fp_cfg);
  362. X    return(0);
  363. }
  364. SHAR_EOF
  365. chmod 0640 feedpipe.c ||
  366. echo 'restore of feedpipe.c failed'
  367. Wc_c="`wc -c < 'feedpipe.c'`"
  368. test 4306 -eq "$Wc_c" ||
  369.     echo 'feedpipe.c: original size 4306, current size' "$Wc_c"
  370. # ============= readcfg.c ==============
  371. sed 's/^X//' << 'SHAR_EOF' > 'readcfg.c' &&
  372. /*
  373. readcfg.c
  374. Written by D'Arcy J.M. Cain
  375. X
  376. Reads configuration file for feedpipe
  377. fills in the fp_cfg array and returns the number of active lines
  378. */
  379. X
  380. #include    <stdio.h>
  381. #include    <stdlib.h>
  382. #include    <string.h>
  383. #include    <ctype.h>
  384. #include    <malloc.h>
  385. #include    "feedpipe.h"
  386. X
  387. int        readcfg(FILE *fp)
  388. {
  389. X    char    *str;
  390. X    int        nents = 0, k;
  391. X
  392. X    if ((fp_cfg = malloc(1)) == NULL)
  393. X        return(0);
  394. X
  395. X    while ((str = xgetline(fp, 1)) != NULL)
  396. X    {
  397. X        if ((fp_cfg = realloc(fp_cfg, sizeof(FP_CFG) * (nents+1))) == NULL)
  398. X        {
  399. X            free(str);
  400. X            return(0);
  401. X        }
  402. X
  403. X        if ((fp_cfg[nents].name = strtok(str, " \t")) == NULL ||
  404. X            (fp_cfg[nents].owner = strtok(NULL, " \t")) == NULL ||
  405. X            (fp_cfg[nents].group = strtok(NULL, " \t")) == NULL )
  406. X        {
  407. X            free(fp_cfg);
  408. X            fprintf(stderr, "%s: Invalid configuration for \"%s\"\n",
  409. X                            progname, str);
  410. X            return(0);
  411. X        }
  412. X
  413. X        if (!strcmp(fp_cfg[nents].owner, "-"))
  414. X            fp_cfg[nents].owner = NULL;
  415. X
  416. X        if (!strcmp(fp_cfg[nents].group, "-"))
  417. X            fp_cfg[nents].group = NULL;
  418. X
  419. X        fp_cfg[nents].cmd = fp_cfg[nents].group;
  420. X
  421. X        while (*fp_cfg[nents].cmd++)
  422. X            ;
  423. X
  424. X        fp_cfg[nents].mode = strtol(fp_cfg[nents].cmd, &fp_cfg[nents].cmd, 0);
  425. X
  426. X        while (isspace(*fp_cfg[nents].cmd))
  427. X            *fp_cfg[nents].cmd++ = 0;
  428. X
  429. X        if (!*fp_cfg[nents].cmd)
  430. X        {
  431. X            free(fp_cfg);
  432. X            fprintf(stderr, "%s: Invalid configuration for \"%s\"\n",
  433. X                            progname, str);
  434. X            return(0);
  435. X        }
  436. X
  437. X        for (k = 0; k < nents; k++)
  438. X        {
  439. X            if (!strcmp(fp_cfg[k].name, fp_cfg[nents].name))
  440. X            {
  441. X                free(fp_cfg);
  442. X                fprintf(stderr, "%s: Duplicate pipe \"%s\"\n", progname, str);
  443. X                return(0);
  444. X            }
  445. X        }
  446. X
  447. X        nents++;
  448. X    }
  449. X
  450. X    if (!nents)
  451. X        free(fp_cfg);
  452. X
  453. X    return(nents);
  454. }
  455. SHAR_EOF
  456. chmod 0640 readcfg.c ||
  457. echo 'restore of readcfg.c failed'
  458. Wc_c="`wc -c < 'readcfg.c'`"
  459. test 1610 -eq "$Wc_c" ||
  460.     echo 'readcfg.c: original size 1610, current size' "$Wc_c"
  461. # ============= getline.c ==============
  462. sed 's/^X//' << 'SHAR_EOF' > 'getline.c' &&
  463. /*
  464. NAME
  465. X    getline, xgetline, wgetline
  466. X
  467. SYNOPSIS
  468. X    char *getline(FILE *fp, int exclusive);
  469. X    char *xgetline(FILE *fp, int exclusive);
  470. X    char *wgetline(WINDOW win, int exclusive);
  471. X
  472. DESCRIPTION
  473. X    Reads a line from the stream given by fp (or from the window given by
  474. X    win in wgetline) and returns a pointer to the string.  There is no
  475. X    length restriction on the returned string.  Space is dynamically
  476. X    allocated for the string as needed.  If the exclusive flag is set then
  477. X    the space won't be reused on the next call.
  478. X
  479. X    In the xgetline version anything from '#' till the end of line is
  480. X    ignored and A  trailing '\' character is treated as a continuation
  481. X    character.  After this processing the resulting line is ignored if
  482. X    it is empty.  The '#' and '\' characters can be included by preceding
  483. X    them with a '\'.  Note that the leading backslash is left in the input
  484. X    string and must be dealt with by the caller.  This can be somewhat of a
  485. X    problem at the end of a line but in general should be workable.
  486. X
  487. X    When the exclusive flag is set the space is made available to the
  488. X    caller on the same basis as malloc(3).  When finished with the
  489. X    string it should be free'ed.
  490. X
  491. RETURNS
  492. X    A pointer to the string without the terminating newline is returned
  493. X    if successful or NULL if there was an error or end of file.  Use
  494. X    feof(3) and ferror(3) to find out if it was a file error, memory
  495. X    allocation problem or EOF condition.
  496. X
  497. AUTHOR
  498. X    D'Arcy J.M. Cain (darcy@druid.UUCP)
  499. X    D'Arcy Cain Consulting
  500. X
  501. CAVEATS
  502. X    This function is in the public domain.
  503. */
  504. X
  505. #include    <stdio.h>
  506. #include    <errno.h>
  507. #include    <malloc.h>
  508. X
  509. /* ascii.h defines the CTRL macro */
  510. #include    <ascii.h>
  511. X
  512. /* I originally was going to use 80 here as the most common case but */
  513. /* decided that a few extra bytes to save a malloc from time to time */
  514. /* would be a better choice.  Comments welcome.  */
  515. #define        CHUNK    128
  516. X
  517. #ifdef    XCAT
  518. #define    XGETLINE_VERSION
  519. #endif
  520. X
  521. #ifdef    CURSES_VERSION
  522. #include    <curses.h>
  523. #ifdef    KANDR
  524. char    *wgetline(win, exclusive)
  525. WINDOW *win;
  526. int exclusive;
  527. #else
  528. char    *wgetline(WINDOW *win, int exclusive)
  529. #endif
  530. #else
  531. #ifdef    XGETLINE_VERSION
  532. #define        getline        xgetline
  533. #endif
  534. #ifdef    KANDR
  535. char    *getline(fp, exclusive)
  536. FILE    *fp;
  537. int        exclusive;
  538. #else
  539. char    *getline(FILE *fp, int exclusive)
  540. #endif
  541. #endif
  542. {
  543. X    static char    *buf = NULL;
  544. X    size_t    sz = CHUNK;        /* this keeps track of the current size of buffer */
  545. X    size_t    i = 0;            /* index into string tracking current position */
  546. X    char    *ptr;            /* since we may set buf to NULL before returning */
  547. X    int        c;                /* to store getc return */
  548. #ifdef    XGETLINE_VERSION
  549. X    int        in_comment = 0;    /* if we are in a comment */
  550. #endif
  551. X
  552. X    /* start out with buf set to CHUNK + 2 bytes */
  553. X    /* note that if this routine was previously called with exclusive */
  554. X    /* set that malloc rather than realloc will be called due to buf */
  555. X    /* being set to NULL in the "if (exclusive) code at end of routine */
  556. X    if (buf == NULL)
  557. X        buf = (char *)(malloc(CHUNK + 2));
  558. X    else
  559. X        buf = (char *)(realloc(buf, CHUNK + 2));
  560. X
  561. X    /* check for memory problem */
  562. X    if (buf == NULL)
  563. X        return(NULL);
  564. X
  565. #ifdef    CURSES_VERSION
  566. X    /* get characters from window until newline or carriage return */
  567. X    while ((c = wgetch(win)) != '\n' && c != '\r')
  568. #else
  569. X    /* get characters from stream until EOF */
  570. #ifdef    XGETLINE_VERSION
  571. X    while ((c = getc(fp)) != EOF)
  572. #else
  573. X    while ((c = getc(fp)) != EOF && c != '\n')
  574. #endif
  575. #endif
  576. X    {
  577. #ifdef    XGETLINE_VERSION
  578. X        buf[i] = c;
  579. X
  580. X        /* new line only way to end comment */
  581. X        if (c == '\n')
  582. X        {
  583. X            if (i)
  584. X                break;
  585. X
  586. X            in_comment = 0;
  587. X        }
  588. X        else if (in_comment)
  589. X        {
  590. X            /* continuation still ends comment - alternative would be silly */
  591. X            if (c == '\\' && (c = getc(fp)) == '\n')
  592. X                in_comment = 0;
  593. X        }
  594. X        else if (c == '#')
  595. X            in_comment = 1;
  596. X        else if (c == '\\')
  597. X        {
  598. X            if ((c = getc(fp)) != '\n' && c != EOF)
  599. X            {
  600. X                buf[i++] = '\\';
  601. X                buf[i++] = c;
  602. X            }
  603. X            else
  604. X                buf[i++] = ' ';
  605. X        }
  606. X        else
  607. X            i++;
  608. X
  609. #else
  610. X        /* the following needed in case we are in cbreak or raw mode */
  611. #ifdef    CURSES_VERSION
  612. X        if (c == CTRL('L'))
  613. X            clearok(win, 1);
  614. X        else
  615. #endif
  616. X        if (c != '\b')
  617. X            buf[i++] = c;
  618. X        else if (i)
  619. X            i--;
  620. #endif
  621. X
  622. X        /* check for buffer overflow */
  623. X        if (i >= sz)
  624. X            if ((buf = (char *)(realloc(buf, (sz += CHUNK) + 2))) == NULL)
  625. X                return(NULL);
  626. X    }
  627. X
  628. X    /* is there anything to return? */
  629. #ifndef    CURSES_VERSION
  630. X    if (c == EOF && !i)
  631. X    {
  632. X        free(buf);
  633. X        buf = NULL;
  634. X        return(NULL);
  635. X    }
  636. #endif
  637. X
  638. X    buf[i++] = 0;    /* yes I want the ++ */
  639. X
  640. X    /* the realloc may be overkill here in most cases - perhaps it */
  641. X    /* should be moved to the 'if (exclusive)' block */
  642. X    ptr = buf = (char *)(realloc(buf, i));
  643. X
  644. X    /* prevent reuse if necessary */
  645. X    if (exclusive)
  646. X        buf = NULL;
  647. X
  648. X    return(ptr);
  649. }
  650. X
  651. /* don't bother with TEST_MODULE if building curses version */
  652. /* most of the testing for the curses version can be done as getline */
  653. #ifdef    TEST_MODULE
  654. int        main(void)
  655. {
  656. X    char    *p;
  657. X
  658. X    while ((p = getline(stdin, 0)) != NULL)
  659. X        printf("%s\n", p);
  660. X
  661. X    return(0);
  662. }
  663. #endif
  664. X
  665. #ifdef    XCAT
  666. #include    <string.h>
  667. X
  668. static void    xcat(FILE *fp)
  669. {
  670. X    char    *p;
  671. X
  672. X    while ((p = xgetline(fp, 0)) != NULL)
  673. X        printf("%s\n", p);
  674. }
  675. X
  676. int        main(int argc, char **argv)
  677. {
  678. X    FILE    *fp;
  679. X    int        k;
  680. X
  681. X    if (argc < 2)
  682. X        xcat(stdin);
  683. X    else for (k = 1; k < argc; k++)
  684. X    {
  685. X        if ((fp = fopen(argv[k], "r")) == NULL)
  686. X            fprintf(stderr, "xcat: Can't open file %s - %s\n",
  687. X                                        argv[k], strerror(errno));
  688. X        else
  689. X        {
  690. X            xcat(fp);
  691. X            fclose(fp);
  692. X        }
  693. X    }
  694. X
  695. X    return(0);
  696. }
  697. #endif
  698. X
  699. SHAR_EOF
  700. chmod 0640 getline.c ||
  701. echo 'restore of getline.c failed'
  702. Wc_c="`wc -c < 'getline.c'`"
  703. test 5377 -eq "$Wc_c" ||
  704.     echo 'getline.c: original size 5377, current size' "$Wc_c"
  705. # ============= Makefile ==============
  706. sed 's/^X//' << 'SHAR_EOF' > 'Makefile' &&
  707. # Makefile for feedpipe
  708. # Written by D'Arcy J.M. Cain
  709. #
  710. X
  711. # If you put getline and friends in your local library as I do then replace
  712. # cain below with the library name.  If not then remove the comment character
  713. # in the OBJECTS list to include xgetline.o there.
  714. LDLIBS =    -lcain
  715. OBJECTS =    feedpipe.o readcfg.o # xgetline.o
  716. X
  717. NAME =        feedpipe
  718. CFLAGS=        -O -Wall -ansi -pedantic -Wcast-qual -Wid-clash-31 \
  719. X            -Wshadow -Wpointer-arith -Wwrite-strings -g
  720. BIN =        /usr/lbin
  721. DIST =        README feedpipe.1 feedpipe.c readcfg.c getline.c Makefile feedpipe.h
  722. feedpipe:    $(OBJECTS)
  723. X
  724. clean:
  725. X    rm  -f *.o *.obj core test
  726. X
  727. clobber:    clean
  728. X    rm -f feedpipe $(NAME).0? $(NAME).gen
  729. X
  730. link:
  731. X    ln $(LBINS) .
  732. X
  733. install:    feedpipe
  734. X    rm -f $(BIN)/feedpipe
  735. X    chmod 711 feedpipe
  736. X    ln feedpipe $(BIN)
  737. X
  738. dist:    gen shar
  739. X
  740. # gen stuff needs my genfiles package
  741. gen:    $(NAME).gen
  742. X
  743. $(NAME).gen:    $(DIST)
  744. X    mkscript $^ > $(NAME).gen
  745. X
  746. shar:    $(NAME).01
  747. X
  748. $(NAME).01:    $(DIST)
  749. X    shar -vxfL 40 -o $(NAME) $^
  750. X    chmod 644 $(NAME).01
  751. X    rm -f /usr/spool/uucppublic/pub/distrib/$(NAME).shar
  752. X    ln $(NAME).01 /usr/spool/uucppublic/pub/distrib/$(NAME).shar
  753. X
  754. strip:    feedpipe
  755. X    strip feedpipe
  756. X
  757. mcs:    feedpipe
  758. X    mcs -d feedpipe
  759. X
  760. # The following is to get the getline source into this directory for
  761. # distribution purposes since it is in my standard library and not
  762. # actually needed for building.
  763. X
  764. getline.c:    ../library/getline.c
  765. X    ln ../library/getline.c .
  766. X
  767. xgetline.o:    getline.c
  768. X    $(CC) $(CFLAGS) -DXGETLINE_VERSION -c getline.c -o xgetline.o
  769. X
  770. # not needed in feedpipe but it's available in getline anyway
  771. wgetline.o:    getline.c
  772. X    $(CC) $(CFLAGS) -DCURSES_VERSION -c getline.c -o wgetline.o
  773. X
  774. SHAR_EOF
  775. chmod 0664 Makefile ||
  776. echo 'restore of Makefile failed'
  777. Wc_c="`wc -c < 'Makefile'`"
  778. test 1613 -eq "$Wc_c" ||
  779.     echo 'Makefile: original size 1613, current size' "$Wc_c"
  780. # ============= feedpipe.h ==============
  781. sed 's/^X//' << 'SHAR_EOF' > 'feedpipe.h' &&
  782. /*
  783. feedpipe.h
  784. Written by D'Arcy J.M. Cain
  785. X
  786. header file for feedpipe
  787. */
  788. X
  789. typedef struct {
  790. X    char    *name;        /* name of the pipe */
  791. X    char    *cmd;        /* command to feed to pipe */
  792. X    char    *owner;        /* file owner */
  793. X    char    *group;        /* file group */
  794. X    int        mode;        /* file mode */
  795. } FP_CFG;
  796. X
  797. extern FP_CFG    *fp_cfg;
  798. extern char        *progname;
  799. extern int        readcfg(FILE *fp);
  800. SHAR_EOF
  801. chmod 0640 feedpipe.h ||
  802. echo 'restore of feedpipe.h failed'
  803. Wc_c="`wc -c < 'feedpipe.h'`"
  804. test 351 -eq "$Wc_c" ||
  805.     echo 'feedpipe.h: original size 351, current size' "$Wc_c"
  806. exit 0
  807. -- 
  808. D'Arcy J.M. Cain (darcy@druid)     |
  809. D'Arcy Cain Consulting             |   There's no government
  810. Toronto, Ontario, Canada           |   like no government!
  811. +1 416 424 2871          DoD#0082  |
  812.  
  813. exit 0 # Just in case...
  814. -- 
  815. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  816. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  817. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  818. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  819.